/******************************************
 * Websanova.com
 *
 * Resources for web entrepreneurs
 *
 * @author          Websanova
 * @copyright       Copyright (c) 2012 Websanova.
 * @license         This websanova color picker jQuery plug-in is dual licensed under the MIT and GPL licenses.
 * @link            http://www.websanova.com
 * @docs            http://www.websanova.com/plugins/websanova/color-picker
 * @version         Version x.x
 *
 ******************************************/
(function($)
{	
	$.fn.wColorPicker = function(settings)
	{
		settings = $.extend({}, $.fn.wColorPicker.defaultSettings, settings || {});
		
		return this.each(function()
		{
			var elem = $(this);	
			var $settings = jQuery.extend(true, {}, settings);
			
			var cp = new ColorPicker($settings);

			cp.generate();

			cp.appendToElement(elem);			
		
			cp.colorSelect(cp, $settings.initColor);
		});
	};

	$.fn.wColorPicker.defaultSettings = {
		color			: 'black', 		// colors - black, white, cream, red, green, blue, yellow, orange, plum
		opacity			: 1,			// opacity level
		initColor		: '#FF0000',	// initial colour to set palette to
		onMouseover		: null,			// function to run when palette color is moused over
		onMouseout		: null,			// function to run when palette color is moused out
		onSelect		: null,			// function to run when palette color is selected
		mode			: 'flat',		// flat mode inserts the palette to container, other modes insert button into container - hover, click
		buttonSize		: 20,			// size of button if mode is ohter than flat
		effect			: 'fade',		// none/slide/fade
		showSpeed		: 500,			// time to run the effects on show
		hideSpeed		: 500			// time to run the effects on hide
	};

	/**
	 * ColorPicker class definition
	 */
	function ColorPicker(settings)
	{ 
		this.colorPicker = null;
		this.settings = settings;
		this.currentColor = settings.initColor;
		this.ralPalette = {};
		
		this.height = null;					// init this, need to get height/width proper while element is still showing
		this.width = null;
		this.slideTopToBottom = null;		// used to assist with sliding in proper direction
		
		this.customTarget = null;			
		this.buttonColor = null;
		this.paletteHolder = null;
		
		return this;
	}
	
	ColorPicker.prototype =
	{
		generate: function ()
		{
			if(this.colorPicker) return this.colorPicker;

			var $this = this;

			var clearFloats = {clear: 'both', height: 0, lineHeight: 0, fontSize: 0}; 

			//custom colors
			this.customTarget = $('<div class="_wColorPicker_customTarget"></div>');
			this.customInput =
			$('<input type="text" readonly style ="width:192px;height:20px;background:none;color:#682300;border:none;" class="_wColorPicker_customInput" value=""/>').keyup(function(e)
			{
				var code = (e.keyCode ? e.keyCode : e.which);
				
				var hex = $this.validHex($(this).val());
				
				$(this).val(hex)
				
				//auto set color in target if it's valid hex code
				if(hex.length == 7) $this.customTarget.css('backgroundColor', hex);
				
				if(code == 13)//set color if user hits enter while on input
				{
					$this.colorSelect($this, $(this).val());
					if($this.buttonColor) $this.hidePalette($this)
				}
			})
			.click(function(e){e.stopPropagation();});
			
			//setup custom area
			var custom = 
			$('<div class="_wColorPicker_custom"></div>')
			//.append(this.appendColors($('<div class="_wColorPicker_noColor">'), ['transparent'], 1))
			.append(this.customTarget.hide())
			.append(this.customInput)
			//clear floats
			.append($('<div></div>').css(clearFloats))

			//grays/simple palette
			var simpleColors = ['9D9D9D', 'F6F6F6'];
			var simplePalette = this.appendColors($('<div class="_wColorPicker_palette_simple"></div>'), simpleColors, 1);
			
      var mixedColors = $.map( RAL_COLOR, function( value, index ) { 
        return index;
      });

			var mixedPalette = this.appendColors($('<div class="_wColorPicker_palette_mixed"></div>'), mixedColors, 18);
			
			//palette container
			var bg = $('<div class="_wColorPicker_bg"></div>').css({opacity: this.settings.opacity});
			var content =
			$('<div class="_wColorPicker_content"></div>')			
			.append(custom)
			.append(simplePalette)
			.append(mixedPalette)
			.append($('<div></div>').css(clearFloats));
			
			//put it all together
			this.colorPicker =
			$('<div class="_wColorPicker_holder"></div>')
			.click(function(e){e.stopPropagation();})
			.append(
				$('<div class="_wColorPicker_outer"></div>')
				.append(
					$('<div class="_wColorPicker_inner"></div>')
					.append( bg )
					.append( content )
				)
			)
			.addClass('_wColorPicker_' + this.settings.color)
			
			return this.colorPicker;
		},
		
		appendColors: function($palette, colors, lineCount)
		{
			var counter = 1;
			var $this = this;
			
			for(index in colors)
			{
				$palette.append(
					$('<div id="_wColorPicker_color_' + counter + '" class="_wColorPicker_color _wColorPicker_color_' + counter + '"></div>').css('backgroundColor', '#' + colors[index])
					.click(function(){$this.colorSelect($this, $(this).css('backgroundColor'));})
					.mouseout(function(e){$this.colorHoverOff($this, $(this));})
					.mouseover(function(){$this.colorHoverOn($this, $(this));})
				);
				
				if(counter == lineCount)
				{
					$palette.append($('<div></div>').css({clear:'both', height:0, fontSize:0, lineHeight:0, marginTop:-1}))
					counter = 0;
				}
				
				counter++;
			}
			
			return $palette;
		},
		
		colorSelect: function($this, color)
		{
			color = $this.toHex(color);;
			var ral_color = RAL_COLOR[color.substring(1).toLowerCase()];
			
			$this.customTarget.css('backgroundColor', color);
			$this.currentColor = color;
			$this.customInput.val('RAL ' + ral_color);
			
			if($this.buttonColor)
			{
				$this.buttonColor.css('backgroundColor', color);
				$this.hidePalette($this);
			} 
			if($this.settings.onSelect) $this.settings.onSelect(color);
		},
		
		colorHoverOn: function($this, $element)
		{
			$element.parent().children('active').removeClass('active');
			$element.addClass('active').next().addClass('activeLeft');
			$element.nextAll('.' + $element.attr('id') + ':first').addClass('activeTop');
			
			var color = $this.toHex($element.css('backgroundColor'));
			var ral_color = RAL_COLOR[color.substring(1).toLowerCase()];

			$this.customTarget.css('backgroundColor', color);
			$this.customInput.val('RAL ' + ral_color);
			
			if($this.settings.onMouseover) $this.settings.onMouseover(color);
		},
		
		colorHoverOff: function($this, $element)
		{
			$element.removeClass('active').next().removeClass('activeLeft')
			$element.nextAll('.' + $element.attr('id') + ':first').removeClass('activeTop')
			var ral_color = RAL_COLOR[$this.currentColor.substring(1).toLowerCase()];
			
			$this.customTarget.css('backgroundColor', $this.currentColor);
			$this.customInput.val('RAL ' + ral_color);
		
			if($this.settings.onMouseout) $this.settings.onMouseout($this.currentColor);
		},
		
		appendToElement: function($element)
		{
			var $this = this;
			
			if($this.settings.mode == 'flat') $element.append($this.colorPicker);
			else
			{
				//setup button
				$this.paletteHolder = $('<div class="_wColorPicker_paletteHolder"></div>').css({position: 'absolute', overflow: 'hidden', width: 1000}).append($this.colorPicker);
				
				$this.buttonColor = $('<div class="_wColorPicker_buttonColor"></div>').css({width: $this.settings.buttonSize, height: $this.settings.buttonSize});
				
				var buttonHolder =
				$('<div class="_wColorPicker_buttonHolder"></div>')
				.css({position: 'relative'})
				.append($('<div class="_wColorPicker_buttonBorder"></div>').append($this.buttonColor))
				.append($this.paletteHolder);

				$element.append(buttonHolder);
				
				$this.width = $this.colorPicker.outerWidth();
				$this.height = $this.colorPicker.outerHeight();
				$this.paletteHolder.css({width: $this.width, height: $this.height}).hide();
				
				if($this.settings.effect == 'fade') $this.paletteHolder.css({opacity: 0});
				
				//setup events
				if($this.settings.mode == 'hover')
				{
					buttonHolder.hover(
						function(e){$this.showPalette(e, $this);},
						function(e){$this.hidePalette($this);}
					)
				}
				else if($this.settings.mode == 'click')
				{
					$(document).click(function(){if($this.paletteHolder.hasClass('active'))$this.hidePalette($this);});
					
					buttonHolder
					.click(function(e)
					{
						e.stopPropagation();
						$this.paletteHolder.hasClass('active') ? $this.hidePalette($this) : $this.showPalette(e, $this);
					});
				}
				
				$this.colorSelect($this, $this.settings.initColor);
			}
		},
		
		showPalette: function(e, $this)
		{
			var offset = $this.paletteHolder.parent().offset();
			
			//init some vars
			var left = 0;
			var top = $this.paletteHolder.parent().outerHeight();
			$this.slideTopToBottom = top;
			
			if(offset.left - $(window).scrollLeft() + $this.width > $(window).width()) left = -1 * ($this.width - $this.paletteHolder.parent().outerWidth());
			if(offset.top - $(window).scrollTop() + $this.height > $(window).height())
			{
				$this.slideTopToBottom = 0;
				top = -1 * ($this.height);
			}
			
			$this.paletteHolder.css({left: left, top: top});
			
			$this.paletteHolder.addClass('active')
			
			if($this.settings.effect == 'slide')
			{
				$this.paletteHolder.stop(true, false).css({height: 0, top: ($this.slideTopToBottom == 0 ? 0 : top)}).show().animate({height: $this.height, top: top}, $this.settings.showSpeed);
			}
			else if($this.settings.effect == 'fade')
			{
				$this.paletteHolder.stop(true, false).show().animate({opacity: 1}, $this.settings.showSpeed);
			}
			else
			{
				$this.paletteHolder.show();
			}
		},
		
		hidePalette: function($this)
		{
			//need this to avoid the double hide when you click on colour (once on click, once on mouse out) - this way it's only triggered once
			if($this.paletteHolder.hasClass('active'))
			{
				$this.paletteHolder.removeClass('active');
				
				if($this.settings.effect == 'slide')
				{
					$this.paletteHolder.stop(true, false).animate({height: 0, top: ($this.slideTopToBottom == 0 ? 0 : $this.slideTopToBottom)}, $this.settings.hideSpeed, function(){$this.paletteHolder.hide()});
				}
				else if($this.settings.effect == 'fade')
				{
					$this.paletteHolder.stop(true, false).animate({opacity: 0}, $this.settings.hideSpeed, function(){$this.paletteHolder.hide()});
				}
				else
				{
					$this.paletteHolder.hide();
				}
			}
		},
		
		toHex: function(color)
		{
			if(color.substring(0,3) == 'rgb')
			{
				var rgb = color.substring(4, color.length - 1).replace(/\s/g, '').split(',');
				
				for(i in rgb)
				{
					rgb[i] = parseInt(rgb[i]).toString(16);
					if((rgb[i]).length < 2) rgb[i] = '0'+rgb[i];
				}
				
				var hex = '#' + rgb.join('').toUpperCase();
			}
			else
			{
				hex = color;//color.substring(0, 1) == '#' ? color.substring(1, color.length) : color;
			}
			
			return  hex;
		},
		
		validHex: function(hex)
		{			
			return '#' + hex.replace(/[^0-9a-f]/ig, '').substring(0,6).toUpperCase();
		}
	}

})(jQuery);

